package cn.com.tarotframework.utils.context;


import lombok.SneakyThrows;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.util.Objects;

/**
 * copyright (C), 2022, 塔罗牌基础架构
 *
 * @program: tarot-demo
 * @author: xincan
 * @date: 2022/12/23 15:06
 * @version: 0.0.1-SNAPSHOT
 * @description: 自定义获取上下文
 */

@Component
public class TarotApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的回调方法，设置上下文环境
     *
     * @param applicationContext spring上下文对象
     * @throws BeansException 抛出spring异常
     */
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        TarotApplicationContextUtil.applicationContext = applicationContext;
    }

    /**
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 获取对象
     *
     * @param name spring配置文件中配置的bean名或注解的名称
     * @return 一个以所给名字注册的bean的实例
     * @throws BeansException 抛出spring异常
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        return (T) applicationContext.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clazz 需要获取的bean的类型
     * @return 该类型的一个在ioc容器中的bean
     * @throws BeansException 抛出spring异常
     */
    public static <T> T getBean(Class<T> clazz) throws BeansException {
        return applicationContext.getBean(clazz);
    }

    /**
     * 如果ioc容器中包含一个与所给名称匹配的bean定义，则返回true否则返回false
     *
     * @param name ioc容器中注册的bean名称
     * @return 存在返回true否则返回false
     */
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }



    /**
     * 获取上下文中的请求真实类
     * @param request 请求方法
     * @author xincan
     * @date 2022/12/23 15:34
     * @return java.lang.String
     */
    @SneakyThrows
    public static String getClass(HttpServletRequest request) {
        //通过ApplicationContext上下文（spring）找到RequestMappingHandlerMapping这个bean
        RequestMappingHandlerMapping handlerMapping = getBean(RequestMappingHandlerMapping.class);
        //RequestMappingHandlerMapping是对应url和处理类方法的一个类
        HandlerExecutionChain handlerChain = handlerMapping.getHandler(request);
        //通过处理链找到对应的HandlerMethod类
        HandlerMethod handler = (HandlerMethod) Objects.requireNonNull(handlerChain).getHandler();
        //HandlerMethod中有bean和method
        return handler.getBean().toString().split("@")[0];//处理请求的类
    }


    /**
     * 获取上下文中的请求方法
     * @param request 请求对象
     * @author xincan
     * @date 2022/12/23 15:33
     * @return java.lang.String
     */
    @SneakyThrows
    public static String getMethod(HttpServletRequest request) {
        //通过ApplicationContext上下文（spring）找到RequestMappingHandlerMapping这个bean
        RequestMappingHandlerMapping handlerMapping = getBean(RequestMappingHandlerMapping.class);
        //RequestMappingHandlerMapping是对应url和处理类方法的一个类
        HandlerExecutionChain handlerChain = handlerMapping.getHandler(request);
        //通过处理链找到对应的HandlerMethod类
        HandlerMethod handler = (HandlerMethod) Objects.requireNonNull(handlerChain).getHandler();
        //HandlerMethod中有bean和method
        return handler.getMethod().getName();//处理请求的方法
    }

}